package com.free.bsf.eureka.client.limitrate.provider;

import com.free.bsf.core.util.LogUtils;
import com.free.bsf.core.util.ThreadUtils;
import com.free.bsf.eureka.client.EurekaProperties;
import com.free.bsf.eureka.client.limitrate.LimitRateConfig;
import com.free.bsf.eureka.client.limitrate.LimitRateException;
import com.free.bsf.eureka.client.limitrate.LimitRateMonitor;
import com.free.bsf.eureka.client.limitrate.LimitRateProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.val;
import lombok.var;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class LocalProvider extends BaseProvider {
    ConcurrentHashMap<String, Counter> cache = new ConcurrentHashMap();
    public LocalProvider(){
        LimitRateMonitor.call("local.cache.count").set(()->{return cache.size();});
        ThreadUtils.system().submit("limitRate重置流量任务",()->{
            var started=0L;
            while (!ThreadUtils.system().isShutdown()) {
                try {
                    for (val kv : cache.entrySet()) {
                        val counter = kv.getValue();
                        counter.periodCounter++;
                        if (counter.periodCounter >= counter.config.getPeriod()) {
                            counter.counter.set(0);
                            counter.periodCounter = 0;
                        }
                    }
                    if(started%10==0) {
                        if (cache.size() > LimitRateProperties.getLimitRateMaxLocalProviderCacheCount()) {
                            throw new LimitRateException("本地限流缓存大小超过" + LimitRateProperties.getLimitRateMaxLocalProviderCacheCount() + ",请检查缓存key是否设置异常或配置调整缓存大小");
                        }
                    }
                } catch (Exception e) {
                    LogUtils.error(LocalProvider.class, EurekaProperties.Project, "本地限流重置流量任务出错", e);
                }
                started++;
                ThreadUtils.sleep(1000);
            }
        });
    }

    @Override
    public boolean add(String key, LimitRateConfig config) {
        return LimitRateMonitor.hook("local").run(key,()->{
            Counter counter = cache.get(key);
            if(counter==null) {
                counter=new Counter(config,0,new AtomicInteger(0));
                cache.put(key, counter);
            }
            //counter.setConfig(config);
            if(counter.counter.incrementAndGet()>counter.config.getMax())
                return false;
            else
                return true;
        });

    }

    @Data
    @AllArgsConstructor
    private static class Counter{
        LimitRateConfig config;
        int periodCounter;
        AtomicInteger counter;
    }
}
